<template>
  <div ref="mapContainer" class="animated-marker-map"></div>
</template>

<script lang="ts">
export default {
  name: 'AnimatedMarkerMap'
}
</script>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import Map from 'ol/Map'
import View from 'ol/View'
import { fromLonLat } from 'ol/proj'
import TileLayer from 'ol/layer/Tile'
import XYZ from 'ol/source/XYZ'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import Feature from 'ol/Feature'
import Point from 'ol/geom/Point'
import { Style, Icon, Circle as CircleStyle, Stroke, Fill } from 'ol/style'
import type { Coordinate } from 'ol/coordinate'

// 地图容器 DOM 引用
const mapContainer = ref<HTMLDivElement | null>(null)
// 地图实例
let map: Map | null = null
// 动画帧ID，用于销毁时取消动画
let animationFrameId: number | null = null

// =====================
// 标记点数据（五个城市）
// =====================
const markerData = [
  { coordinate: fromLonLat([116.397428, 39.90923]) }, // 北京
  { coordinate: fromLonLat([121.473701, 31.230416]) }, // 上海
  { coordinate: fromLonLat([113.264385, 23.129112]) }, // 广州
  { coordinate: fromLonLat([114.085947, 22.547]) },    // 深圳
  { coordinate: fromLonLat([104.066541, 30.572269]) }  // 成都
]

// =====================
// 创建矢量图层（带动画参数的 feature）
// =====================
const createVectorLayer = () => {
  // 每个点 feature 都带有动画参数
  const features = markerData.map(marker => {
    return new Feature({
      geometry: new Point(marker.coordinate),
      // iconOpacity: 图标透明度（闪烁）
      // ringRadius: 圆环半径（扩散）
      // ringOpacity: 圆环透明度（扩散）
      iconOpacity: 1,
      ringRadius: 20,
      ringOpacity: 0.6
    })
  })

  // style 返回两个 Style：一个圆环，一个图标
  return new VectorLayer({
    source: new VectorSource({ features }),
    style: (feature) => {
      // 取动画参数
      const iconOpacity = feature.get('iconOpacity') ?? 1
      const ringRadius = feature.get('ringRadius') ?? 20
      const ringOpacity = feature.get('ringOpacity') ?? 0.6
      // 图标样式（只做透明度动画，scale 固定为 1）
      const iconStyle = new Icon({
        src: '/vite.svg',
        scale: 1,
        opacity: iconOpacity,
        anchor: [0.5, 0.5],
        anchorXUnits: 'fraction',
        anchorYUnits: 'fraction'
      })
      // 扩散圆环样式（半径和透明度动画）
      const ringStyle = new CircleStyle({
        radius: ringRadius,
        stroke: new Stroke({ color: `rgba(255,0,0,${ringOpacity})`, width: 3 }),
        fill: new Fill({ color: `rgba(0,153,255,${ringOpacity * 0.15})` })
      })
      // 先画圆环，再画图标
      return [
        new Style({ image: ringStyle }),
        new Style({ image: iconStyle })
      ]
    }
  })
}

// =====================
// 动画函数：更新 feature 的动画参数并触发重绘
// =====================
const animate = (vectorLayer: VectorLayer<VectorSource>) => {
  const features = vectorLayer.getSource()?.getFeatures()
  if (!features) return
  const now = Date.now()
  features.forEach((feature, idx) => {
    // 图标透明度闪烁（呼吸灯效果）
    // 0.6~1.0 之间周期变化
    const iconOpacity = 0.6 + 0.4 * Math.abs(Math.sin(now / 600 + idx))
    // 圆环扩散动画
    // period: 一个完整扩散周期（毫秒）
    const period = 1500
    // t: 当前周期进度（0~1）
    const t = ((now + idx * 300) % period) / period
    // 半径 20~50 线性变化
    const ringRadius = 20 + t * 30
    // 透明度 0.5~0 线性变化
    const ringOpacity = 0.5 * (1 - t)
    // 更新 feature 的动画参数
    feature.set('iconOpacity', iconOpacity)
    feature.set('ringRadius', ringRadius)
    feature.set('ringOpacity', ringOpacity)
  })
  // 触发图层重绘
  vectorLayer.changed()
  // 下一帧继续动画
  animationFrameId = requestAnimationFrame(() => animate(vectorLayer))
}

// =====================
// 地图初始化和动画启动
// =====================
onMounted(() => {
  if (!mapContainer.value) return
  // 创建地图实例
  map = new Map({
    target: mapContainer.value,
    layers: [
      // 高德地图底图
      new TileLayer({
        source: new XYZ({
          url: 'https://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7',
          maxZoom: 18
        })
      })
    ],
    view: new View({
      center: fromLonLat([116.397428, 39.90923]), // 北京为中心
      zoom: 5
    })
  })
  // 添加动画点图层
  const vectorLayer = createVectorLayer()
  map.addLayer(vectorLayer)
  // 启动动画
  animate(vectorLayer)
})

// =====================
// 组件销毁时清理动画和地图
// =====================
onBeforeUnmount(() => {
  if (animationFrameId !== null) {
    cancelAnimationFrame(animationFrameId)
  }
  if (map) {
    map.setTarget(undefined)
    map = null
  }
})
</script>

<style scoped>
.animated-marker-map {
  width: 100%;
  height: 100%;
}
</style> 